package com.example.artemis.events;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 简单的事件发布器
 * 提供同步和异步事件发布功能
 */
public class EventPublisher {

    private static final Logger logger = LoggerFactory.getLogger(EventPublisher.class);

    // 使用线程安全的列表存储监听器
    private final List<EventListener<? extends MessageEvent>> listeners = new CopyOnWriteArrayList<>();

    // 异步处理线程池
    private final ExecutorService asyncExecutor = Executors.newCachedThreadPool(r -> {
        Thread thread = new Thread(r, "EventPublisher-Async-" + System.currentTimeMillis());
        thread.setDaemon(true); // 设置为守护线程，不阻止JVM退出
        return thread;
    });

    /**
     * 注册事件监听器
     *
     * @param listener 要注册的监听器
     * @param <T>      事件类型
     */
    public <T extends MessageEvent> void registerListener(EventListener<T> listener) {
        if (listener != null) {
            listeners.add(listener);
            logger.debug("注册事件监听器: {} (事件类型: {})",
                    listener.getListenerName(), listener.getEventType().getSimpleName());
        }
    }

    /**
     * 注销事件监听器
     *
     * @param listener 要注销的监听器
     */
    public void unregisterListener(EventListener<? extends MessageEvent> listener) {
        if (listeners.remove(listener)) {
            logger.debug("注销事件监听器: {}", listener.getListenerName());
        }
    }

    /**
     * 发布事件（同步）
     *
     * @param event 要发布的事件
     * @param <T>   事件类型
     */
    @SuppressWarnings("unchecked")
    public <T extends MessageEvent> void publishEvent(T event) {
        if (event == null) {
            logger.warn("尝试发布null事件，忽略");
            return;
        }

        logger.debug("发布事件: {}", event.getEventType());

        // 查找并通知所有匹配的监听器
        for (EventListener<? extends MessageEvent> listener : listeners) {
            try {
                // 检查监听器是否支持该事件类型
                if (listener.getEventType().isInstance(event)) {
                    logger.debug("通知监听器 {} 处理事件: {}",
                            listener.getListenerName(), event.getEventType());
                    ((EventListener<T>) listener).handleEvent(event);
                }
            } catch (Exception e) {
                logger.error("监听器 {} 处理事件 {} 时发生错误",
                        listener.getListenerName(), event.getEventType(), e);
                // 继续处理其他监听器，不因为一个监听器失败而中断
            }
        }
    }

    /**
     * 异步发布事件
     *
     * @param event 要发布的事件
     * @param <T>   事件类型
     */
    public <T extends MessageEvent> void publishEventAsync(T event) {
        if (event == null) {
            logger.warn("尝试异步发布null事件，忽略");
            return;
        }

        logger.debug("异步发布事件: {}", event.getEventType());

        asyncExecutor.submit(() -> {
            try {
                publishEvent(event);
            } catch (Exception e) {
                logger.error("异步处理事件 {} 时发生错误", event.getEventType(), e);
            }
        });
    }

    /**
     * 获取已注册的监听器数量
     *
     * @return 监听器数量
     */
    public int getListenerCount() {
        return listeners.size();
    }

    /**
     * 获取指定类型的监听器数量
     *
     * @param eventType 事件类型
     * @return 监听器数量
     */
    public int getListenerCount(Class<? extends MessageEvent> eventType) {
        return (int) listeners.stream()
                .filter(listener -> listener.getEventType().equals(eventType))
                .count();
    }

    /**
     * 关闭事件发布器，释放资源
     */
    public void shutdown() {
        logger.info("关闭事件发布器...");

        // 清空监听器列表
        listeners.clear();

        // 关闭线程池
        asyncExecutor.shutdown();

        logger.info("事件发布器已关闭");
    }

    /**
     * 强制关闭事件发布器（立即停止）
     */
    public void shutdownNow() {
        logger.warn("强制关闭事件发布器...");

        listeners.clear();
        asyncExecutor.shutdownNow();

        logger.info("事件发布器已强制关闭");
    }

    /**
     * 检查发布器是否已关闭
     *
     * @return 如果已关闭返回true
     */
    public boolean isShutdown() {
        return asyncExecutor.isShutdown();
    }
}